#include "CDataConnection.h"


CDataConnection* CDataConnection::NewL(RSocketServ& aSocketServ,TDesC& aServerName, TUint aNodeid, TUint aPort, TUint aInterval, MDisplayObserver& aDisplay, MGpsObserver& aGpsObserver)
{
	CDataConnection * self = new (ELeave) CDataConnection (aSocketServ, aServerName, aNodeid, aPort, aInterval, aDisplay, aGpsObserver);
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop();
	return self;	
}

CDataConnection::CDataConnection(RSocketServ& aSocketServ, TDesC& aServerName, TUint aNodeid, TUint aPort, TUint aInterval, MDisplayObserver& aDisplay, MGpsObserver& aGpsObserver):CActive(EPriorityStandard), iSocketServ(aSocketServ), iServerName(aServerName), iNodeid(aNodeid), iPort(aPort), iInterval(aInterval), iDisplay(aDisplay), iGpsObserver(aGpsObserver)
{
	
}

CDataConnection::~CDataConnection()
{
	Stop();
	iTimmer.Close(); 
	
	//if (buffer_info_cell) delete buffer_info_cell;
	/*
	if (iDataCellId) {
		delete iDataCellId;
		iDataCellId = NULL;
	} */
	
	#ifdef __LOGGER
		iLog.Write(_L("CDataConnection destroyed"));
		iLog.CloseLog();
		iLog.Close();
	#endif
}
void CDataConnection::ConstructL()
{
	CActiveScheduler::Add( this );
  	iState = EDataIdle;
  	User::LeaveIfError(iTimmer.CreateLocal());
  	#ifdef __LOGGER
	  	iLog.Connect();
		iLog.CreateLog(_L("findme"),_L("CDataConnection.txt"),EFileLoggingModeOverwrite);
	#endif
		
	//iDataCellId = CDataCellId::NewL();
	iChangingInterval = EFalse;

	iNode.version=1;
	iNode.reserved=0;
	iNode.deviceid = iNodeid;
	iNode.gpsdata.latitude = 0;
	iNode.gpsdata.longitude = 0;
}

TInt CDataConnection::Start()
{
	TBuf<32> inter;
	inter.Num(iInterval);
	iDisplay.DisplayStatus(EInterval, inter);
	
	
	TInt err;
	if (iState == EDataIdle)
	{
		iDisplay.DisplayStatus(EStatus, _L("Connecting"));
		#ifdef __LOGGER
			iLog.WriteFormat (_L("Connecting to :"));
			iLog.Write(iServerName);
			iLog.WriteFormat(_L("Port=%d"),iPort);
		#endif
		err = iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp);
		if (err != KErrNone) {
			return err;
		}
		iResolver.GetByName(iServerName, iHostAddress, iStatus) ;
		iState = EDataResolving;
		SetActive();
	}
	return KErrNone;
}


void CDataConnection::RunL()
{
	#ifdef __LOGGER
		iLog.WriteFormat(_L("RunL. iState/iStatus = %d/%d"), iState,iStatus);
	#endif
	if (iStatus == KErrNone)
	{
		switch (iState)
		{
		case EDataIdle:
			// Shouldn't happen
			break ;
		case EDataResolving:
			iInetAddress = iHostAddress().iAddr;
			iInetAddress.SetPort(iPort);
			
			if (iSocket.Open(iSocketServ,KAfInet,KSockDatagram,KProtocolInetUdp) != KErrNone) {
				iDisplay.DisplayStatus(EStatus, _L("Error : open"));
				#ifdef __LOGGER
					iLog.Write(_L("Error opening socket"));
				#endif
				this->Stop();
				return;
			}
			/* From http://wiki.forum.nokia.com/index.php/Using_the_sockets_API#Using_unconnected_sockets_2
			 * (Note: A client stream socket which connects to a server does not need to call Bind().
			 * The local address of a client stream socket will be set as part of the connection process.)
			err = iSocket.Bind(iInetAddress); */
			SendData();
			iDisplay.DisplayStatus(EStatus, _L("Sending data"));
			break;
		case EDataSending:
			SendData();
			break;
		case EDataWaiting:
			#ifdef __LOGGER
				iLog.Write(_L("To sleep"));
			#endif
			iTimmer.After(iStatus,iInterval * 1000000);
			iState=EDataSending;
			SetActive(); 	
		}
	}
	else if (iStatus == KErrCancel)
	{
		#ifdef __LOGGER
			iLog.Write(_L("WRN: Something was canceled."));
		#endif
		if (iChangingInterval != EFalse) {
			iChangingInterval=EFalse;
			SendData();
		}
	}
	else
	{
		#ifdef __LOGGER
			iLog.WriteFormat(_L("Error code=%d"),iStatus);
		#endif
		if (iState == EDataResolving) {
			iDisplay.DisplayStatus(EStatus, _L("Server not found"));
			this->Stop();
			this->Start();
			return;
		}
		else {
			this->Stop();
		}
	}
}

void CDataConnection::SendData()
{
	#ifdef __LOGGER
		iLog.Write(_L("Sending DData..."));
	#endif
	iGpsObserver.getData(iNode.gpsdata.latitude, iNode.gpsdata.longitude, iGpsFix);
	iNode.reserved = iGpsFix;
	TInt size = sizeof(struct _device);
	iLog.WriteFormat(_L("size : %d"), size);
	TPtr8 pDataNode((unsigned char*)&iNode,size,size);
	iSocket.SendTo(pDataNode,iInetAddress,0,iStatus);
	iState=EDataWaiting;
	SetActive();
}

void CDataConnection::DoCancel()
{
	#ifdef __LOGGER
		iLog.Write(_L("Inside DoCancel."));
	#endif
	if ( iState == EDataResolving ){
		#ifdef __LOGGER
			iLog.Write(_L("Cancel iResolver."));
		#endif
		iResolver.Cancel();
	}
	else if (iState == EDataWaiting){
		#ifdef __LOGGER
			iLog.Write(_L("Cancel iSocket."));
		#endif
		iSocket.CancelAll();
	}	
	else if (iState == EDataSending){
		#ifdef __LOGGER
			iLog.Write(_L("Cancel iTimmer."));
		#endif
		iTimmer.Cancel();
	}
	else{
		#ifdef __LOGGER
			iLog.Write(_L("Error: Nothing to cancel."));
		#endif
	}
}

void CDataConnection::CloseConnection()
{
	if (iState != EDataIdle)
	{
		iResolver.Close();
		iSocket.Close();
		iState = EDataIdle;
		#ifdef __LOGGER
			iLog.Write(_L("DataConnection closed."));
		#endif
	}
}

void CDataConnection::Stop()
{
	if(IsActive())	
	{
		#ifdef __LOGGER
			iLog.Write(_L("CActive was active. Canceling..."));
		#endif
		Cancel(); // It calls DoCancel
	}
	#ifdef __LOGGER
		iLog.Write(_L("CActive is not active."));
	#endif
	CloseConnection();
}

TBool CDataConnection::IsRunning()
{
	if ( iState == EDataIdle ) return EFalse;
	else return ETrue;
}

void CDataConnection::setNodeid(TUint aNodeid)
{
	iNode.deviceid = aNodeid;
	updateScreen();
}

void CDataConnection::setInterval(TUint aInterval)
{
	iInterval = aInterval;
	if (iState == EDataSending && iChangingInterval == EFalse) { 
		iTimmer.Cancel();
		iChangingInterval=ETrue;
	}
	updateScreen();
}

void CDataConnection::setServer(const TDesC& aServerName) 
{
	iServerName.Zero();
	iServerName.Copy(aServerName);
	updateScreen();
}

void CDataConnection::setPort(TUint aPort) {
	iPort=aPort;
	updateScreen();
}

void CDataConnection::updateScreen()
{
	TBuf<64> text;
	text.Num(iNode.deviceid);
	iDisplay.DisplayStatus(ENodeid, text);
	text.Num(iInterval);
	iDisplay.DisplayStatus(EInterval, text);
}